----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    15:21:13 03/09/2012 
-- Design Name: 
-- Module Name:    ALU - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity ALU is
    Port ( ALUINa : in  STD_LOGIC_VECTOR (7 downto 0);
           ALUINb : in  STD_LOGIC_VECTOR (7 downto 0);
			  NUM_ROT : in STD_LOGIC_VECTOR (2 downto 0);
           is_Shift : in  STD_LOGIC;
           carry_in : in STD_LOGIC;
           opType : in  STD_LOGIC_VECTOR (2 downto 0);
			  ALUout : out  STD_LOGIC_VECTOR (7 downto 0);
			  flagsOUT : out STD_LOGIC_VECTOR (1 downto 0));		  
end ALU;

architecture Behavioral of ALU is
---------------------------OP_SLL---------------------------
function fn_sll (ALUINa,NROTACIONES : in STD_LOGIC_VECTOR; carry: in STD_LOGIC) return STD_LOGIC_VECTOR is
		variable tempOut : STD_LOGIC_VECTOR (8 downto 0);
		variable carry_flag: STD_LOGIC;
		variable num_rot : Integer;
		begin
		carry_flag := carry;
		tempOut := carry & ALUINa;
		num_rot := conv_integer (NROTACIONES);
		while num_rot > 0 loop
			tempOut := tempOut(7 downto 0) & carry_flag;
			carry_flag := tempOut (8);
			num_rot:= num_rot-1;
		end loop;
		return tempOut;
	end function fn_sll;
	
--------------------------OP_SRL-----------------------------
function fn_srl (ALUINa,NROTACIONES : in STD_LOGIC_VECTOR; carry: in STD_LOGIC) return STD_LOGIC_VECTOR is
		variable tempOut : STD_LOGIC_VECTOR (8 downto 0);
		variable carry_flag: STD_LOGIC;
		variable num_rot : Integer;
		begin
		carry_flag := carry;
		tempOut := ALUINa & carry;
		num_rot := conv_integer (NROTACIONES);
		while num_rot > 0 loop
			tempOut :=  carry_flag & tempOut(8 downto 1);
			carry_flag := tempOut (0);
			num_rot:= num_rot-1;
		end loop;
		return tempOut;
	end function fn_srl;
	
--------------------------OP_SLA-----------------------------
function fn_sla (ALUINa,NROTACIONES : in STD_LOGIC_VECTOR; carry: in STD_LOGIC) return STD_LOGIC_VECTOR is
		variable tempOut : STD_LOGIC_VECTOR (8 downto 0);
		variable carry_flag: STD_LOGIC;
		variable num_rot : Integer;
		begin
		carry_flag := carry;
		tempOut := carry & ALUINa;
		num_rot := conv_integer (NROTACIONES);
		while num_rot > 0 loop
			tempOut :=  tempOut(7 downto 0) & tempOut (0);
			carry_flag := tempOut (8);
			num_rot:= num_rot-1;
		end loop;
		return tempOut;
	end function fn_sla;
	
--------------------------OP_SRA-----------------------------
function fn_sra (ALUINa,NROTACIONES : in STD_LOGIC_VECTOR; carry: in STD_LOGIC) return STD_LOGIC_VECTOR is
		variable tempOut : STD_LOGIC_VECTOR (8 downto 0);
		variable carry_flag: STD_LOGIC;
		variable num_rot : Integer;
		begin
		carry_flag := carry;
		tempOut := ALUINa & carry;
		num_rot := conv_integer (NROTACIONES);
		while num_rot > 0 loop
			tempOut := tempOut (8) & tempOut(8 downto 1);
			carry_flag := tempOut (0);
			num_rot:= num_rot-1;
		end loop;
		return tempOut;
	end function fn_sra;
	

--------------------------OP_ROL-----------------------------
function fn_rol (ALUINa,NROTACIONES : in STD_LOGIC_VECTOR; carry: in STD_LOGIC) return STD_LOGIC_VECTOR is
		variable tempOut : STD_LOGIC_VECTOR (8 downto 0);
		variable carry_flag: STD_LOGIC;
		variable num_rot : Integer;
		begin
		carry_flag := carry;
		tempOut := carry & ALUINa;
		num_rot := conv_integer (NROTACIONES);
		while num_rot > 0 loop
			tempOut := tempOut(7 downto 0) & tempOut (8);
			carry_flag := tempOut (8);
			num_rot:= num_rot-1;
		end loop;
		return tempOut;
	end function fn_rol;
	
--------------------------OP_ROR-----------------------------
function fn_ror (ALUINa,NROTACIONES : in STD_LOGIC_VECTOR; carry: in STD_LOGIC) return STD_LOGIC_VECTOR is
		variable tempOut : STD_LOGIC_VECTOR (8 downto 0);
		variable carry_flag: STD_LOGIC;
		variable num_rot : Integer;
		begin
		carry_flag := carry;
		tempOut := ALUINa & carry;
		num_rot := conv_integer (NROTACIONES);
		while num_rot > 0 loop
			tempOut := tempOut (0) & tempOut(8 downto 1);
			carry_flag := tempOut (0);
			num_rot:= num_rot-1;
		end loop;
		return tempOut;
	end function fn_ror;
	
begin

	process(ALUINa, ALUINb, is_Shift, opType, carry_in)
		variable tempOut : STD_LOGIC_VECTOR (8 downto 0);
		variable auxCarry :STD_LOGIC_VECTOR (8 downto 0);
		variable zero_flag: STD_LOGIC;
		variable carry_flag: STD_LOGIC;
		begin
		
			if carry_in = '1' then
				auxCarry := "000000001";
				carry_flag := '1';
			else
				auxCarry := "000000000";
				carry_flag := '0';
			end if;
		
			if is_Shift = '1' then
				case opType is
					when "000" => tempOut := fn_sll (ALUINa, NUM_ROT, carry_flag);
										ALUout <= tempOut (7 downto 0);
										carry_flag := tempOut (8);
					when "001" => tempOut := fn_srl (ALUINa, NUM_ROT, carry_flag);
										ALUout <= tempOut (8 downto 1);
										carry_flag := tempOut (0);
               when "010" => tempOut := fn_sla (ALUINa, NUM_ROT, carry_flag);
										ALUout <= tempOut (7 downto 0);
										carry_flag := tempOut (8);
               when "011" => tempOut := fn_sra (ALUINa, NUM_ROT, carry_flag);
										ALUout <= tempOut (8 downto 1);
										carry_flag := tempOut (0);
					when "100" => tempOut := fn_rol (ALUINa, NUM_ROT, carry_flag);
              						ALUout <= tempOut (7 downto 0);
										carry_flag := tempOut (8); 
					when "101" => tempOut := fn_ror (ALUINa, NUM_ROT, carry_flag);
										ALUout <= tempOut (8 downto 1);
										carry_flag := tempOut (0);
					when others => tempOut := (others => '0');
				end case;
			else
				case opType is
					when "000" => tempOut := sxt(ALUINa,9) + sxt(ALUINb,9);
										ALUout <= tempOut (7 downto 0);
										carry_flag := tempOut (8);
					when "001" => tempOut := sxt(ALUINa,9) + sxt(ALUINb,9) + auxCarry;			
										ALUout <= tempOut (7 downto 0);
										carry_flag := tempOut (8);
					when "010" => tempOut := sxt(ALUINa,9) - sxt(ALUINb,9);
										ALUout <= tempOut (7 downto 0);
										carry_flag := tempOut (8);					
					when "011" => tempOut := sxt(ALUINa,9) - sxt(ALUINb,9) + auxCarry;
										ALUout <= tempOut (7 downto 0);
										carry_flag := tempOut (8);					
					when "100" => tempOut := carry_in & (ALUINa and ALUINb);
										ALUout <= tempOut (7 downto 0);
										carry_flag := tempOut (8);
					when "101" => tempOut := carry_in & (ALUINa or ALUINb);
										ALUout <= tempOut (7 downto 0);
										carry_flag := tempOut (8);
					when "110" => tempOut := carry_in & (ALUINa xor ALUINb);
										ALUout <= tempOut (7 downto 0);
										carry_flag := tempOut (8);
					when others => tempOut := (others => '0');
				end case;
			end if;
			
			if (tempOut (7 downto 0) = "00000000") then 
				zero_flag := '1';
			else
				zero_flag := '0';
			end if;
			
			flagsOUT <= zero_flag & carry_flag;
	end process;

end Behavioral;



